package com.my.netty.basic.eventloop;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import lombok.extern.slf4j.Slf4j;

import java.nio.charset.Charset;

@Slf4j
public class EventLoopServer {
    /*
        EventLoop处理IO事件
     */
    public static void main(String[] args) {
        //细分2：实际项目中，往往一个EventLoop管理大量的channel，如果某个channel上有耗时较长的业务操作，会导致其他channel的IO出现长时间等待
        //因此对于复杂的业务操作，一般不交给处理IO的EventLoop执行，而是创建专门处理业务的EventLoopGroup
        EventLoopGroup bizGroup = new DefaultEventLoopGroup();

        new ServerBootstrap()
            //细分1：group方法支持传入两个EventLoopGroup，此时第一个EventLoopGroup就是Boss，只处理accept事件；
            // 第二个EventLoopGroup就是Worker只处理读写事件，构造方法参数用于指定线程池线程数
            .group(new NioEventLoopGroup(1), new NioEventLoopGroup(2))
            .channel(NioServerSocketChannel.class)
            .childHandler(new ChannelInitializer<NioSocketChannel>() {
                @Override
                protected void initChannel(NioSocketChannel sc) throws Exception {
                    log.info("获取客户端连接：{}", sc.remoteAddress());
                    sc.pipeline().addLast("handler1", new ChannelInboundHandlerAdapter() {
                        @Override
                        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                            //处理读事件，由于没有Decoder，msg是ByteBuf类型，可通过有参toString转为字符串
                            ByteBuf buf = (ByteBuf) msg;
                            //注意打印的线程名，同一个channel一定是被同一个EventLoop处理
                            log.info("接收客户端{}发送数据: {}", ctx.channel().remoteAddress(), buf.toString(Charset.defaultCharset()));

                            //将消息传递给下个Handler，自定义Handler时需要
                            ctx.fireChannelRead(msg);
                        }
                    }).addLast(bizGroup,"handler2", new ChannelInboundHandlerAdapter() {
                        //在pipeline上添加ChannelHandler时，可以传入一个参数EventLoopGroup，表示使用指定的EventLoopGroup执行任务
                        @Override
                        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                            ByteBuf buf = (ByteBuf) msg;
                            log.info("handler2处理数据{}",  buf.toString(Charset.defaultCharset()));

                        }
                    });
                }
            })
            .bind(8080);
        log.info("服务器已启动...");
    }
}
